import { buffer } from "@kit.ArkTS";

export const recordEventMessage = buffer.from(
  "AAAA0AAAAFX31gVLDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcAB1JlY29yZHMNOmNvbnRlbnQtdHlwZQcAGGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTEsRm9vLFdoZW4gbGlmZSBnaXZlcyB5b3UgZm9vLi4uCjIsQmFyLG1ha2UgQmFyIQozLEZpenosU29tZXRpbWVzIHBhaXJlZCB3aXRoLi4uCjQsQnV6eix0aGUgaW5mYW1vdXMgQnV6eiEKzxKeSw==",
  "base64"
);

export const statsEventMessage = buffer.from(
  "AAAA0QAAAEM+YpmqDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcABVN0YXRzDTpjb250ZW50LXR5cGUHAAh0ZXh0L3htbDxTdGF0cyB4bWxucz0iIj48Qnl0ZXNTY2FubmVkPjEyNjwvQnl0ZXNTY2FubmVkPjxCeXRlc1Byb2Nlc3NlZD4xMjY8L0J5dGVzUHJvY2Vzc2VkPjxCeXRlc1JldHVybmVkPjEwNzwvQnl0ZXNSZXR1cm5lZD48L1N0YXRzPiJ0pLk=",
  "base64"
);

export const endEventMessage = buffer.from(
  "AAAAOAAAACjBxoTUDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcAA0VuZM+X05I=",
  "base64"
);

export const exception = buffer.from(
  "AAAAtgAAAF8BcW64DTpjb250ZW50LXR5cGUHABhhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0NOm1lc3NhZ2UtdHlwZQcACWV4Y2VwdGlvbg86ZXhjZXB0aW9uLXR5cGUHAAlFeGNlcHRpb25UaGlzIGlzIGEgbW9kZWxlZCBleGNlcHRpb24gZXZlbnQgdGhhdCB3b3VsZCBiZSB0aHJvd24gaW4gZGVzZXJpYWxpemVyLj6Gc60=",
  "base64"
);

export class MockEventMessageSource implements AsyncIterable<Uint8Array> {
  private readonly data: Uint8Array;
  private readonly emitSize: number;
  private readonly throwError?: Error;
  private readCount = 0;
  constructor(options: MockEventMessageSourceOptions) {
    this.data = new Uint8Array(buffer.concat(options.messages).buffer)
    this.emitSize = options.emitSize;
    this.throwError = options.throwError;
  }

  async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {
    while (this.readCount < this.data.byteLength){

      const bytesLeft = this.data.byteLength - this.readCount;
      const numBytesToSend = Math.min(bytesLeft, this.emitSize);

      const chunk = this.data.slice(this.readCount, this.readCount + numBytesToSend);
      this.readCount += numBytesToSend;
      yield chunk;
    }
    if (this.throwError) {
      // process.nextTick(function () {
      //   self.emit("error", new Error("Throwing an error!"));
      // });
      throw Error("Throwing an error!")
    }
  }
}

export interface MockEventMessageSourceOptions {
  messages: Array<buffer.Buffer>;
  emitSize: number;
  throwError?: Error;
}


export const source = async function* () {
  yield new Uint8Array(recordEventMessage.buffer);
  yield new Uint8Array(statsEventMessage.buffer);
  yield new Uint8Array(endEventMessage.buffer);
};

export const exceptionSource = async function* () {
  yield new Uint8Array(exception.buffer);
};

export const recordEventSource = async function* () {
  yield new Uint8Array(recordEventMessage.buffer);
};